
public class nodeList<T> {
	private Node<T> start;
	//constructors
	public nodeList(){
		start = null;
	}
	public nodeList(T info){
		start = new Node<T>(info);
	}
	//start
	private static Node getStart(nodeList chain){
		return chain.start;
	}
	public T getStartInfo(){
		if (start == null)
			return null;
		return this.start.getInfo();
	}
	public void insertNodeToStart(Node<T> pos){
		pos.setNext(start);
		this.start = pos;
	}
	public void insertInfoToStart(T info){
		Node<T> n = new Node<T>(info,this.start);
		this.start=n;
	}
	public void setStartInfo(T info){
		if (start == null)
			start = new Node<T>(info);
		else
			this.start.setInfo(info);
	} 
	public void delStart(){
		if (start == null)
			return;
		this.start = this.start.getNext();
	}
	public void delStartInfo(){
		if (start == null)
			return;
		this.start.setInfo(null);
	}
	public void insertChainInStart(nodeList<T> chain){
		if (chain.start == null)
			return;
		int i=0;
		for (Node<T> pos = chain.start; pos != null; pos = pos.getNext()){
			this.insertInfoInIndex(pos.getInfo(), i);
			i++;
		}
	}
	public void addChainInStart(nodeList<T> chain){
		if (chain.start == null){
			this.insertInfoToStart(null);
			return;
		}
		int i=0;
		for (Node<T> pos = chain.start; pos != null; pos = pos.getNext()){
			this.setIndexInfo(pos.getInfo(), i);
			i++;
		}
	}
	//End
	public Node<T> getEnd(){
		if (start == null)
			return null;
		Node<T> pos = this.start;
		while (pos.getNext() != null)
			pos = pos.getNext();
		return pos; 
	}
	public T getEndInfo(){//if (start=null)-> getEnd()=null??-> pos=nul??-> error
		Node<T> pos = this.getEnd();
		return pos.getInfo(); 
	}
	public void insertNodeToEnd(Node<T> toInsert){
		if (this.start == null){
			insertNodeToStart(toInsert);
			return;
		}
		toInsert.setNext(null);
		this.getEnd().setNext(toInsert);
	}
	public void insertInfoToEnd(T toInsert){
		if (this.start == null){
			insertInfoToStart(toInsert);
			return;
		}
		Node<T> pos = new Node<T>(toInsert);
		this.getEnd().setNext(pos);
	}
	public void setEndInfo(T info){
		this.getEnd().setInfo(info);
	}
	public void delEnd(){
		if (start == null)
			return;
		Node<T> pos = this.start;
		while (pos.getNext().getNext() != null)
			pos = pos.getNext();
		pos.setNext(null);
	}
	public void delEndInfo(){
		if (start == null)
			return;
		this.getEnd().setInfo(null);
	}
	//index
	public Node<T> getIndex(int index){
		if (index > this.length())
			return this.getEnd();
		if (start == null)
			return null;
		Node<T> pos = this.start;
		for (;index > 0; index--)
			pos = pos.getNext();
		return pos;
	}
	public T getIndexInfo(int index){
		if (start == null)
			return null;
		return this.getIndex(index).getInfo();
	}
	public void insertNodeInIndex(Node<T> toInsert,int index){
		if ((index == 0) || (start == null)){
			this.insertNodeToStart(toInsert);
			return;
		}
		if (index > this.length()){
			this.insertNodeToEnd(toInsert);
			return;
		}
		toInsert.setNext(this.getIndex(index));
		this.getIndex((index-1)).setNext(toInsert);
	}
	public void insertInfoInIndex(T info,int index){
		if (index == 0){
			this.insertInfoToStart(info);
			return;
		}
		
		if (index == this.length()+1){
			this.insertInfoToEnd(info);
			return;
		}
		if (index > this.length()+1){
			for (int i=index-1; i>this.length();i--){
				this.insertInfoToEnd(null);
			}
			this.insertInfoToEnd(info);
			return;
		}
		Node<T> toInsert = new Node<T>(info,this.getIndex(index));
		this.getIndex((index-1)).setNext(toInsert);
	}
	public void setIndexInfo(T info,int index){
		if (start == null){
			this.setStartInfo(info);
			return;
		}
		if (index == this.length()){
			this.setEndInfo(info);
			return;
		}
		if (index == this.length()+1){
			this.insertInfoToEnd(info);
			return;
		}
		if (index > this.length()+1){
			for (int i=index-1; i>this.length();i--){
				this.insertInfoToEnd(null);
			}
			this.insertInfoToEnd(info);
			return;
		}
		this.getIndex(index).setInfo(info);
	}
	public void delIndex(int index){
		if (start == null)
			return;
		if (index == 0){
			this.delStart();
			return;
		}
		if (index == this.length()){
			this.delEnd();
			return;
		}
		if (index > this.length())
			return;
		this.getIndex(index-1).setNext(this.getIndex(index+1));
	}
	public void delIndexInfo(int index){
		if (index > this.length())
			return;
		this.setIndexInfo(null, index);
	}
	//general
	/**
	 * @return the length of the nodeList
	 */
	public int length(){
		if (this.start == null)
			return 0;
		int i=0;
		for (Node<T> pos = start; pos.getNext() != null; pos = pos.getNext())
			i++;	
		return (i);
	}
	public String toString() {
		String s="";
		Node<T> pos = start;
		while (pos != null) {
			s += pos.getInfo();
			pos = pos.getNext();
			if (pos != null) s += ", ";
		}
		return s;
	}
	//chain
	/**
	 * add nodeList after the last node of the correct nodeList
	 * @param chain The nodList to add
	 */
	public void insertChainToEnd(nodeList<T> chain){
		Node<T> pos = this.start;
		while (pos.getNext() != null)
			pos = pos.getNext();
		pos.setNext(chain.start);
	}
	/**
	 * create new nodeList begin in the "n" node
	 * @param n The number of the node to start the new nodeList
	 * @return the new nodeList
	 */
	public nodeList<T> beginFromIndex(int indexToStart){
		nodeList<T> chain = new nodeList<T>();
		
		return chain;
	}
	//Character
	public static void compressSequences(nodeList<Character> chain){
		Node<Character> pos = chain.start;
		//follow loop
		while(pos.getNext() != null){
			//delete loop 
			while(pos.getInfo() == pos.getNext().getInfo())
				pos.setNext(pos.getNext().getNext());
			pos=pos.getNext();
		}
	}
	//Integer
	public void mergeIntNodeListIntoThis(nodeList<Integer> chain){
		if (chain.start == null)
			return;
		while(chain.start != null){
			
			chain.start=chain.start.getNext();
		}
	}
	public static nodeList<Integer> mergeIntNodeList(nodeList<Integer> chain1,nodeList<Integer> chain2){
		Node<Integer> pos1 = chain1.start;
		Node<Integer> pos2 = chain2.start;
		nodeList<Integer> merge = new nodeList<Integer>();
		while ((pos1 != null) && (pos2 != null)){
			if (pos1.getInfo() > pos2.getInfo()){
				merge.insertInfoToEnd(pos2.getInfo());
				pos2=pos2.getNext();
			}
			else {
				merge.insertInfoToEnd(pos1.getInfo());
				pos1=pos1.getNext();
			}
		}
		if (pos1 == null){
			if (pos2 != null)
				merge.insertNodeToEnd(pos2);//merge.getEnd.setNext(pos2);
		}
		else{
			if (pos1 != null)
				merge.insertNodeToEnd(pos1);//merge.getEnd.setNext(pos1);
		}
		return merge;
	}
	public static void sortMerge(nodeList<Integer> chain){
		if (chain.length()==1)
			return;
		if (chain.length()==2){
			if (chain.start.getInfo() <= chain.start.getNext().getInfo())
				return;
			chain.start.getNext().setNext(chain.start);
			chain.start=chain.start.getNext();
			return;
			}
	}
}
